home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / Apps / DevTools / eText5 / Source / Document.subproj / note < prev    next >
Encoding:
Text File  |  1994-09-30  |  10.4 KB  |  324 lines

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //    FILENAME:    eTDocInfo.m
  3. //    SUMMARY:    Implementation of eTNavinfo objects; stringTable I/O.
  4. //    SUPERCLASS:    Object:HashTable:NXStringTable:eTDocInfo
  5. //    PROTOCOLS:    None
  6. //    AUTHOR:        Rohit Khare
  7. //    COPYRIGHT:    (c) 1994 California Institure of Technology, eText Project
  8. ///////////////////////////////////////////////////////////////////////////////
  9. //    IMPLEMENTATION
  10. //        eTDocInfo is built atop NXStringTable, but implementation should be
  11. //    completely private and abstracted away. 
  12. ///////////////////////////////////////////////////////////////////////////////
  13. //    HISTORY
  14. //    07/20/94:    Added LaTeX support.
  15. //    07/10/94:    Added support for HTML header/trailer writing
  16. //    01/10/94:    Created. See Actors/eTNavinfo
  17. ///////////////////////////////////////////////////////////////////////////////
  18.  
  19. #import "eTDocInfo.h"
  20. #import "Navigator.h"
  21.  
  22. @implementation eTDocInfo
  23.  
  24. //     char    path[MAXPATHLEN];
  25. //     BOOL    readOnly;
  26. //     long    docID;
  27.  
  28. // Accessor Methods
  29. - (long) docID
  30.     {return docID;}
  31. - (NXAtom) docIDStr
  32.     {return [self valueForStringKey:DOCID];}
  33. - (NXAtom) title
  34.     {return [self valueForStringKey:TITLE];}
  35. - (NXAtom) author
  36.     {return [self valueForStringKey:AUTHOR];}
  37. - (NXAtom) agent
  38.     {return [self valueForStringKey:AGENT];}
  39. - (NXAtom) parent
  40.     {return [self valueForStringKey:PARENT];}
  41. - (NXAtom) peers
  42.     {return [self valueForStringKey:PEERS];}
  43. - (NXAtom) keywords
  44.     {return [self valueForStringKey:KEYWORDS];}
  45. - (NXAtom) rtfComments
  46.     {return [self valueForStringKey:COMMENTS];}
  47.     // ASCII-coded RTF source of comment field
  48. - (STR) comments
  49. {    // ASCII contents of comment field
  50.     static char comments[1024];
  51.     NXStream *stream;
  52.     id theText = [NXApp sharedText];
  53.  
  54.     stream = NXOpenMemory([self valueForStringKey:COMMENTS],
  55.              strlen([self valueForStringKey:COMMENTS]), NX_READONLY);
  56.     [theText readRichText:stream];
  57.     NXClose(stream);
  58.     [theText getSubstring:comments start:0 length:1023];
  59.     comments[1023]=0;
  60.     return comments;
  61. }
  62. - (NXAtom) valueOf: (NXAtom) theQuery
  63. {
  64.     NXAtom tmp = [self valueForStringKey:theQuery];
  65.     return (tmp ? tmp : NXUniqueString(""));
  66. }
  67.  
  68. // Dynamic Bits
  69. - (STR)    path
  70.     {return path;}
  71. - (BOOL) readOnly
  72.     {return readOnly = (BOOL) access(path, W_OK);}
  73.  
  74. // Setter Methods
  75. - setPath:(const char *) newPath
  76. {
  77.     if ([self title] == NXUniqueString("Unsaved Doc")) {
  78.         char tmp[MAXPATHLEN];    // C Programmer's Disease
  79.         strncpy(tmp, rindex(newPath, '/')+1, MAXPATHLEN);
  80.         *rindex(tmp, '.') = 0; 
  81.         [self setTitle:tmp];
  82.     }
  83.     strncpy(path, newPath, MAXPATHLEN); 
  84.     // how do we tell eTNavinfoUI its info has been invalidated?
  85.     return self;
  86. }
  87. - setTitle:(const char *) newTitle
  88.     {[self insertKey:TITLE value:NXUniqueString(newTitle)]; return self;}
  89. - setAuthor:(const char *) newAuthor
  90.     {[self insertKey:AUTHOR value:NXUniqueString(newAuthor)]; return self;}
  91. - setAgent:(const char *) newAgent
  92.     {[self insertKey:AGENT value:NXUniqueString(newAgent)]; return self;}
  93. - setParent:(const char *) newParent
  94.     // ASCII-coded docID of parent etNavinfo
  95.     {[self insertKey:PARENT value:NXUniqueString(newParent)]; return self;}
  96. - setPeers:(const char *) newPeers
  97.     // ASCII-coded, space between each docID
  98.     {[self insertKey:PEERS value:NXUniqueString(newPeers)]; return self;}
  99. - setKeywords:(const char *) newKeywords
  100.     {[self insertKey:KEYWORDS value:NXUniqueString(newKeywords)]; return self;}
  101. - setComments:(const char *) newComments
  102.     // ASCII-coded RTF source of comment field
  103.     {[self insertKey:COMMENTS value:NXUniqueString(newComments)]; return self;}
  104. - bindKey:(const char *) newKey to: (const char *) newVal
  105.     {[self insertKey:NXUniqueString(newKey) value:NXUniqueString(newVal)];
  106.      return self;}
  107.  
  108. // Searching Methods
  109. - (BOOL) searchFor:(NXAtom) regex in:(NXAtom) field    // field == "*" means any
  110. {    // Note that we search the RTF-coded comments field
  111.     // -- not the ascii-filtered version
  112.     BOOL found = NO;
  113.     
  114.     //special-case speed-up
  115.     // REWRITE REST OF CODE TO USE 2 RE_COMP's RATHER THAN !recmp
  116.     if (re_comp(regex))
  117.         return NO;
  118.     if ((field == ANYFIELD) &&
  119.         (re_exec([self valueForStringKey:TITLE]) || 
  120.          re_exec([self valueForStringKey:PARENT]) ||
  121.          re_exec([self valueForStringKey:KEYWORDS]) ||
  122.          re_exec([self valueForStringKey:DOCID]) ||
  123.          re_exec([self valueForStringKey:AUTHOR]) ||
  124.          re_exec([self valueForStringKey:AGENT]) ||
  125.          re_exec([self valueForStringKey:PEERS]) ||
  126.          re_exec([self valueForStringKey:COMMENTS])))
  127.         return YES;
  128.     if (!recmp(field, DOCID))
  129.         found |= !strcmp(regex, [self valueForStringKey:DOCID]);
  130.     if (!found && !strcmp(field, PARENT))
  131.         found |= !strcmp(regex, [self valueForStringKey:PARENT]);
  132.     if (!found && !strcmp(field, TITLE))
  133.         found |= !strcmp(regex, [self valueForStringKey:TITLE]);
  134.     if (!found && !strcmp(field, AUTHOR))
  135.         found |= !strcmp(regex, [self valueForStringKey:AUTHOR]);
  136.     if (!found && !strcmp(field, AGENT))
  137.         found |= !strcmp(regex, [self valueForStringKey:AGENT]);
  138.     if (!found && !strcmp(field, PEERS))
  139.         found |= !strcmp(regex, [self valueForStringKey:PEERS]);
  140.     if (!found && !strcmp(field, KEYWORDS))
  141.         found |= !strcmp(regex, [self valueForStringKey:KEYWORDS]);
  142.     if (!found && !strcmp(field, COMMENTS))
  143.         found |= !strcmp(regex, [self valueForStringKey:COMMENTS]);
  144.     return found;
  145. }
  146.  
  147. // Input/Output Methods
  148. - init
  149. {
  150.     char    idStr[9];
  151.     struct    passwd *p;
  152.     [super init];
  153.     path[0] = 0;
  154.     docID = [NXApp uniqueID];
  155.     sprintf(idStr,"%x", docID);
  156.     [self insertKey:DOCID value:(char *)NXUniqueString(idStr)];
  157.     [self insertKey:TITLE
  158.             value:NXUniqueString("Unsaved Doc")];
  159.     p = getpwuid(getuid());
  160.     if (p->pw_name)
  161.         [self insertKey:AUTHOR value:NXUniqueString(p->pw_gecos)];
  162.     else [self insertKey:AUTHOR value:NXUniqueString("Author's Name")];
  163.     [self insertKey:AGENT value:NXUniqueString("")];
  164.     [self insertKey:PARENT value:NXUniqueString("")];
  165.     [self insertKey:PEERS value:NXUniqueString("")];
  166.     [self insertKey:KEYWORDS value:NXUniqueString("Index Terms")];
  167.     [self insertKey:COMMENTS
  168.         value:NXUniqueString("{\\rtf0\\ansi{\\fonttbl\\f1\\fnil Times-Roman;\\f2\\fswiss Helvetica;}\n\\margl40\n\\margr40\n\\pard\\tx520\\tx1060\\tx1600\\tx2120\\tx2660\\tx3200\\tx3720\\tx4260\\tx4800\\tx5320\\f1\\b0\\i\\ulnone\\fs24\\fc0\\cf0 Rich-Text \n\\b comments\n\\b0  about this document\n}\n")];
  169.     readOnly = NO;
  170.     [[NXApp navigator] registerNavinfo:self];
  171.     return self;    
  172. }
  173.  
  174. - free
  175. {
  176.     //sanity check
  177.     char * foo = [self valueForStringKey:DOCID];
  178.     if (foo) sscanf(foo, "%x", &docID);
  179.     if (foo && [[NXApp navigator] navinfoFor:docID] != self)
  180.         return [super free];
  181.     return self;    
  182. }
  183. - initFromDoc:(const STR) pathname
  184. {
  185.     char    navinfoPath[MAXPATHLEN];
  186.     
  187.     [super init];
  188.     strncpy(path, pathname, MAXPATHLEN);
  189.     sprintf(navinfoPath, "%s/%s", path, NAVINFO);
  190.     if (access(navinfoPath, R_OK | F_OK)) {
  191.         // backward-compatibility with PR1 documents.
  192.         sprintf(navinfoPath, "%s/etNavinfo", path);
  193.     }
  194.     if (access(navinfoPath, R_OK | F_OK)) {
  195.         [NXApp delayedFree:self];
  196.         return nil;
  197.     }
  198.     if (![self readFromFile:navinfoPath]) {
  199.         [NXApp delayedFree:self];
  200.         return nil;
  201.     }
  202.     sscanf([self valueForStringKey:DOCID], "%x", &docID);
  203.     if ([[NXApp navigator] navinfoFor:docID]){
  204.         [NXApp delayedFree:self];
  205.         return [[NXApp navigator] navinfoFor:docID];
  206.     }
  207.     else [[NXApp navigator] registerNavinfo:self];
  208.     return self;
  209. }
  210.  
  211. - writeToDoc:(const STR) pathname    // Passing in null is ok; uses last path
  212. {
  213.     char    navinfoPath[MAXPATHLEN];
  214.     
  215.     sprintf(navinfoPath, "%s/%s", pathname ? pathname : path, NAVINFO);
  216.     [self writeToFile:navinfoPath];
  217.     return self;
  218. }
  219.  
  220. - writeToDoc { return [self writeToDoc:NULL];}    // "Hidden" API
  221.  
  222. - writeHTMLHeader:(NXStream *)s
  223. {
  224.     char tmp[MAXPATHLEN];
  225.     long dID;
  226.     id     dNI;
  227.     id   NIlist;
  228.     NXAtom peers;
  229.     int    i;
  230.  
  231.     NXPrintf(s,"<HEAD>\n<TITLE>%v</TITLE>\n",[self title]);
  232.     
  233.     // does eTNavinfo have etfLink objects handy? -- no, it doesn't.
  234.     strcpy(tmp, [self parent]);
  235.     sscanf(tmp, "%x", &dID);
  236.     dNI = [[NXApp navigator] navinfoFor:dID];
  237.     if (dNI) {
  238.         strcpy(tmp, [dNI path]);
  239.         *rindex(tmp,'.')=0;
  240.         NXPrintf(s,"<LINK HREF=\"../%s.htmd/TXT.html\" REL=\"Parent\" TITLE=\"%v\">\n", rindex(tmp,'/')+1,[dNI title]);
  241.     }
  242.     
  243.     NIlist = [[NXApp navigator] query:[self docIDStr] field:PARENT];
  244.     i = [NIlist count];
  245.     for (;i;i--) {
  246.         strcpy(tmp, [[NIlist objectAt:(i-1)] path]);
  247.         *rindex(tmp,'.')=0;
  248.         NXPrintf(s,"<LINK HREF=\"../%s.htmd/TXT.html\" REL=\"Child\" TITLE=\"%v\">\n", rindex(tmp,'/')+1,[[NIlist objectAt:(i-1)] title]);
  249.     }
  250.  
  251.     // continue for "peer" documents?
  252.     // for peers, we get a list of doc IDs that are space-separated
  253.     i=0; peers = [self peers];
  254.     while (peers[i] && (1 == sscanf(peers+i,"%x",&dID))) {
  255.         dNI = [[NXApp navigator] navinfoFor:dID];
  256.         if (dNI) {
  257.             strcpy(tmp, [dNI path]);
  258.             *rindex(tmp,'.')=0;
  259.         NXPrintf(s,"<LINK HREF=\"../%s.htmd/TXT.html\" REL=\"Peer\" TITLE=\"%v\">\n", rindex(tmp,'/')+1,[dNI title]);
  260.         }
  261.         while(peers[i] && (peers[i] != ' ')) i++;  //skip ahead
  262.     }
  263.         
  264.     NXPrintf(s,"</HEAD>\n");
  265.     return self;
  266. }
  267.  
  268. - writeHTMLTrailer:(NXStream *)s
  269. {
  270.     char tmp[MAXPATHLEN];
  271.     long dID;
  272.     id     dNI;
  273.     id   NIlist;
  274.     NXAtom peers;
  275.     int    i;
  276.  
  277.     // we should try to check the user's preferences here
  278.     // we use a hole to tunnel through to a switch in the UI
  279.     // if (trailerSw)
  280.     // write HR, then parent, peers, then author, date, then
  281.     NXPrintf(s,"\n\n<!-- TRAILER -->\n<HR>\n<DL COMPACT>\n");
  282.  
  283.     strcpy(tmp, [self parent]);
  284.     sscanf(tmp, "%x", &dID);
  285.     dNI = [[NXApp navigator] navinfoFor:dID];
  286.     if (dNI) {
  287.         strcpy(tmp, [dNI path]);
  288.         *rindex(tmp,'.')=0;
  289.         NXPrintf(s,"\n<DT>Parent:</DT>\n<DD><A HREF=\"../%s.htmd/TXT.html\">%v</A></DD>\n", rindex(tmp,'/')+1,[dNI title]);
  290.     }
  291.     
  292.     NIlist = [[NXApp navigator] query:[self docIDStr] field:PARENT];
  293.     i = [NIlist count];
  294.     if ([NIlist count]) NXPrintf(s,"\n<DT>Children:</DT>\n");
  295.     for (;i;i--) {
  296.         strcpy(tmp, [[NIlist objectAt:(i-1)] path]);
  297.         *rindex(tmp,'.')=0;
  298.         NXPrintf(s,"\n<DD><A HREF=\"../%s.htmd/TXT.html\">%v</A></DD>\n", rindex(tmp,'/')+1,[[NIlist objectAt:(i-1)] title]);
  299.     }
  300.     
  301.     // for peers, we get a list of doc IDs that are space-separated
  302.     i=0; peers = [self peers];
  303.     if(strlen(peers)) NXPrintf(s,"\n<DT>See Also:</DT>\n");;
  304.     while (peers[i] && (1 == sscanf(peers+i,"%x",&dID))) {
  305.         dNI = [[NXApp navigator] navinfoFor:dID];
  306.         if (dNI) {
  307.             strcpy(tmp, [dNI path]);
  308.             *rindex(tmp,'.')=0;
  309.         NXPrintf(s,"\n<DD><A HREF=\"../%s.htmd/TXT.html\">%v</A></DD>\n", rindex(tmp,'/')+1,[dNI title]);
  310.         }
  311.         while(peers[i] && (peers[i] != ' ')) i++;  //skip ahead
  312.     }
  313.     NXPrintf(s,"</DL>\n");
  314.     
  315.     NXPrintf(s,"<HR><A HREF=\"http://www.etext.caltech.edu/\">Created by the eText Engine, version %v</A><P>%v\n", [NXApp version], [NXApp date]);
  316.     return self;
  317. }
  318.  
  319. - writeLaTeXHeader:(NXStream *)s
  320. {    
  321.     NXPrintf(s, "\n\\author{%w}\n\\title{%w}\n\\maketitle\n",[self author], [self title]);
  322.     return self;
  323. }
  324. @end